package com.wzdigit.wms.raw.service.inv;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.framework.utils.RedisUtil;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.GoodsIsHoldEnum;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.inv.CreateOrUpdateHoldHeaderRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldDtlListForWaitFreezeByAsnRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldDtlListForWaitFreezeByLotnoRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldDtlListForWaitFreezeByOqcRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldDtlListForWaitFreezeBySkuRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldDtlListRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldFreezeRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchHoldHeaderRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchInvHoldByAsnRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchInvHoldByOqcRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchInvHoldBySkuRequest;
import com.wzdigit.wms.basic.client.request.inv.SubmitHoldFreezeRequest;
import com.wzdigit.wms.basic.client.request.inv.SubmitHoldFreezeRequest.SubmitHoldFreezeItemRequest;
import com.wzdigit.wms.basic.client.request.inv.SubmitHoldThawRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.inv.HoldDtlGoodsResponse;
import com.wzdigit.wms.basic.client.response.inv.HoldDtlListForWaitFreezeResponse;
import com.wzdigit.wms.basic.client.response.inv.HoldDtlListResponse;
import com.wzdigit.wms.basic.client.response.inv.HoldErrorGoodsResponse;
import com.wzdigit.wms.basic.client.response.inv.HoldHeaderResponse;
import com.wzdigit.wms.basic.client.response.inv.InvHoldByAsnResponse;
import com.wzdigit.wms.basic.client.response.inv.InvHoldByLontnoResponse;
import com.wzdigit.wms.basic.client.response.inv.InvHoldByOqcResponse;
import com.wzdigit.wms.basic.client.response.inv.InvHoldBySkuResponse;
import com.wzdigit.wms.basic.domain.basic.Location;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inv.HoldDtl;
import com.wzdigit.wms.basic.domain.inv.HoldDtlGoods;
import com.wzdigit.wms.basic.domain.inv.HoldHeader;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsLog;
import com.wzdigit.wms.basic.domain.inventory.GoodsVersion;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.order.TrsnDtl;
import com.wzdigit.wms.basic.domain.order.TrsnDtlGoods;
import com.wzdigit.wms.basic.domain.order.TrsnHeader;
import com.wzdigit.wms.basic.enums.GoodsStatusEnum;
import com.wzdigit.wms.basic.enums.OpCodeEnum;
import com.wzdigit.wms.basic.enums.TransferDtlGoodStatusEnum;
import com.wzdigit.wms.basic.enums.TrsnDtlInvUpdateFlagEnum;
import com.wzdigit.wms.basic.enums.TrsnDtlStatusEnum;
import com.wzdigit.wms.basic.enums.TrsnHeaderStatusEnum;
import com.wzdigit.wms.basic.enums.TrsnNoteTypeEnum;
import com.wzdigit.wms.basic.enums.inv.HoldDtlGoodsStatusEnum;
import com.wzdigit.wms.basic.enums.inv.HoldDtlStatusEnum;
import com.wzdigit.wms.basic.enums.inv.HoldHeaderStatusEnum;
import com.wzdigit.wms.basic.mapper.core.basic.LocationMapper;
import com.wzdigit.wms.basic.mapper.core.inv.HoldDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.inv.HoldDtlMapper;
import com.wzdigit.wms.basic.mapper.core.inv.HoldHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.GoodsLogMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.GoodsMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.manager.GoodsHoldMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnDtlMapper;
import com.wzdigit.wms.basic.mapper.core.order.TrsnHeaderMapper;
import com.wzdigit.wms.basic.service.code.GoodsVersionService;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.util.DateUtils;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.basic.util.WrapperUtil;
import com.wzdigit.wms.basic.util.common.LockNumber;
import com.wzdigit.wms.basic.util.common.SeparatorString;
import com.wzdigit.wms.common.utils.EasyExcelUtil;
import com.wzdigit.wms.raw.service.wmscommon.core.GoodsService;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 库存冻结/解冻-服务类
 * 
 * @author yangdongjie
 * @GdnService.java
 * @2021年2月24日下午3:25:03
 */
@Service
public class HoldService {

	@Autowired
	private HoldHeaderMapper holdHeaderMapper;

	@Autowired
	private HoldDtlMapper holdDtlMapper;
	
	@Autowired
	private HoldDtlGoodsMapper holdDtlGoodsMapper;
	
	@Autowired
	private GoodsHoldMapper goodsHoldMapper;
	
	@Autowired
	private LocationMapper locationMapper;
	
	@Autowired
	private GoodsService goodsService;
	
	@Autowired
    private TrsnHeaderMapper trsnHeaderMapper;
	
	@Autowired
    private TrsnDtlMapper trsnDtlMapper;
	
	@Autowired
    private TrsnDtlGoodsMapper trsnDtlGoodsMapper;
	
	@Autowired
	private GoodsMapper goodsMapper;
	
	@Autowired
	private GoodsLogMapper goodsLogMapper;
	
	@Autowired
	private InventoryService inventoryService;
	
	@Autowired
	private LotnoService lotnoService;
	
	@Autowired
	private GoodsVersionService goodsVersionService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	private static final String TRSN_ORDER = "TRSN_ORDER";			// 创建凭证编码
	
	/**
	 * 主档查询
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldHeaderResponse>> selectHoldHeaderList(SearchHoldHeaderRequest dto, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		Date beginCreateDate = null, endCreateDate = null;
		if (dto.getBeginCreateTime() != null) {
			beginCreateDate = DateUtils.getStartTime(dto.getBeginCreateTime());
		}
		if (dto.getEndCreateTime() != null) {
			endCreateDate = DateUtils.getEndTime(dto.getEndCreateTime());
		}
		PagerInfo<List<HoldHeaderResponse>> pagerInfo = new PagerInfo<>();
		List<HoldHeaderResponse> list = holdHeaderMapper.selectAll(dto, beginCreateDate, endCreateDate);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	/**
	 * 创建/修改主档
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<Integer> createOrUpdateHoldHeader(CreateOrUpdateHoldHeaderRequest dto, HttpServletRequest servletRequest) {
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();

		HoldHeader holdHeader = new HoldHeader();
		BeanUtil.copy(dto, holdHeader);
		if (holdHeader.getHoldHeaderId() == null) {
			holdHeader.setStatus(HoldHeaderStatusEnum.CREATE.code);
			holdHeader.setCreateTime(date);
			holdHeader.setCreateUser(loginName);
			holdHeaderMapper.insert(holdHeader);
		} else {
			holdHeader.setModifyTime(date);
			holdHeader.setModifyUser(loginName);
			holdHeaderMapper.updateById(holdHeader);
		}
		return new Result<>(holdHeader.getHoldHeaderId());
	}
	
	/**
	 * 删除主档
	 * 
	 * @param
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> deleteHoldHeader(Integer holdHeaderId, HttpServletRequest servletRequest) {
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();

		HoldHeader holdHeader = holdHeaderMapper.selectById(holdHeaderId);
		holdHeader.setStatus(HoldHeaderStatusEnum.ABANDONED.code);
		holdHeader.setModifyTime(date);
		holdHeader.setModifyUser(loginName);
		holdHeaderMapper.updateById(holdHeader);
		return new Result<>();
	}
	
	/**
	 * 明细查询
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlListResponse>> selectHoldDtlList(SearchHoldDtlListRequest dto, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		Date beginHoldDate = null, endHoldDate = null;
		if (dto.getBeginHoldTime() != null) {
			beginHoldDate = DateUtils.getStartTime(dto.getBeginHoldTime());
		}
		if (dto.getEndHoldTime() != null) {
			endHoldDate = DateUtils.getEndTime(dto.getEndHoldTime());
		}
		PagerInfo<List<HoldDtlListResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlListResponse> list = holdDtlMapper.selectAll(dto, beginHoldDate, endHoldDate);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	/**
	 * 序号明细查询
	 * 
	 * @param holdDtlId
	 * @param goodsSn
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlGoodsResponse>> selectHoldDtlGoodsList(Integer holdDtlId, String goodsSn, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		PagerInfo<List<HoldDtlGoodsResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlGoodsResponse> list = holdDtlGoodsMapper.selectByHoldDtlId(holdDtlId, goodsSn);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	/**
	 * 待冻结明细==>序号明细查询
	 * 
	 * @param dto
	 * @param goodsSn
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlGoodsResponse>> selectHoldDtlGoodsListForWaitFreeze(SearchHoldFreezeRequest dto) {
		SubmitHoldFreezeItemRequest item = dto.getItem();
		List<SubmitHoldFreezeItemRequest> itemList = new ArrayList<>(1);
		itemList.add(item);
		
		Page<?> page = PageHelper.offsetPage(dto.getSkipCount(), dto.getMaxResultCount());
		List<HoldDtlGoodsResponse> list = null;
		switch (dto.getType()) {
		case 1:
			// 按送货单
			item.setAsnNoList(Arrays.asList(item.getAsnNo().split(SeparatorString.COMMA)));
			list = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeByAsn(itemList, dto.getGoodsSn());
			break;
		case 2:
			// 按检验单
			item.setOqcList(Arrays.asList(item.getOqc().split(SeparatorString.COMMA)));
			list = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeByOqc(itemList, dto.getGoodsSn());
			
			// 查找一同冻结的检验单
			/*for (HoldDtlGoodsResponse one : list) {
				List<OqcAndGoodsQtyDto> otherList = asnReceiveDtlGoodsMapper.selectOqcAndGoodsQty(one.getGoodsSn());
				otherList = otherList.stream().filter(o -> !item.getOqcList().contains(o.getOqc())).collect(Collectors.toList());
				if(otherList.size() > 0) {
					String common = otherList.toString();
					common = common.replaceAll("OqcAndGoodsQtyDto", "");
					common = common.replaceAll("oqc=", "单号：");
					common = common.replaceAll("qty=", "数量：");
					common = String.format("与检验单%s的SN[%s]一同冻结", common, one.getGoodsSn());
					one.setCommon(common);
				}
			}*/
			break;
		case 3:
			// 按物料/批次号
			list = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeBySkuOrLotno(itemList, dto.getGoodsSn());
			break;
		default:
			Shift.fatal("入参有误，请确认！");
			break;
		}
		PagerInfo<List<HoldDtlGoodsResponse>> pagerInfo = new PagerInfo<>();
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	
	
	/*1*/
	/**
	 * 送货单冻结物料选择
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<InvHoldByAsnResponse>> selectInvHoldByAsn(SearchInvHoldByAsnRequest dto, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		Date beginRcvDate = null, endRcvDate = null;
		if (dto.getBeginRcvTime() != null) {
			beginRcvDate = DateUtils.getStartTime(dto.getBeginRcvTime());
		}
		if (dto.getEndRcvTime() != null) {
			endRcvDate = DateUtils.getEndTime(dto.getEndRcvTime());
		}
		PagerInfo<List<InvHoldByAsnResponse>> pagerInfo = new PagerInfo<>();
		List<InvHoldByAsnResponse> list = goodsHoldMapper.selectInvHoldByAsn(dto, beginRcvDate, endRcvDate);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	/**
	 * 送货单冻结物料选择=》统计待冻结明细
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlListForWaitFreezeResponse>> selectHoldDtlListForWaitFreezeByAsn(SearchHoldDtlListForWaitFreezeByAsnRequest dto) {
		// 因为入库单有供应商，收料之后，条码不设置供应商
		dto.getItemList().stream().forEach(item -> {
			item.setVendorId(null);
		});
		Page<?> page = PageHelper.offsetPage(dto.getSkipCount(), dto.getMaxResultCount());
		PagerInfo<List<HoldDtlListForWaitFreezeResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlListForWaitFreezeResponse> list = goodsHoldMapper.selectHoldDtlListForWaitFreezeByAsn(dto.getItemList());
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	
	/*2*/
	/**
	 * 检验单冻结物料选择
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<InvHoldByOqcResponse>> selectInvHoldByOqc(SearchInvHoldByOqcRequest dto, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		Date beginInspEndDate = null, endInspEndDate = null;
		if (dto.getBeginInspEndTime() != null) {
			beginInspEndDate = DateUtils.getStartTime(dto.getBeginInspEndTime());
		}
		if (dto.getEndInspEndTime() != null) {
			endInspEndDate = DateUtils.getEndTime(dto.getEndInspEndTime());
		}
		PagerInfo<List<InvHoldByOqcResponse>> pagerInfo = new PagerInfo<>();
		List<InvHoldByOqcResponse> list = goodsHoldMapper.selectInvHoldByOqc(dto, beginInspEndDate, endInspEndDate);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	/**
	 * 检验单冻结物料选择=》统计待冻结明细
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlListForWaitFreezeResponse>> selectHoldDtlListForWaitFreezeByOqc(SearchHoldDtlListForWaitFreezeByOqcRequest dto) {
		// 因为入库单有供应商，收料之后，条码不设置供应商
		dto.getItemList().stream().forEach(item -> {
			item.setVendorId(null);
		});
		Page<?> page = PageHelper.offsetPage(dto.getSkipCount(), dto.getMaxResultCount());
		PagerInfo<List<HoldDtlListForWaitFreezeResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlListForWaitFreezeResponse> list = goodsHoldMapper.selectHoldDtlListForWaitFreezeByOqc(dto.getItemList());
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	
	/*3*/
	/**
	 * 料号冻结物料选择
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<InvHoldBySkuResponse>> selectInvHoldBySku(SearchInvHoldBySkuRequest dto, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		PagerInfo<List<InvHoldBySkuResponse>> pagerInfo = new PagerInfo<>();
		List<InvHoldBySkuResponse> list = goodsHoldMapper.selectInvHoldBySku(dto);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	/**
	 * 料号冻结物料选择=》统计待冻结明细
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlListForWaitFreezeResponse>> selectHoldDtlListForWaitFreezeBySku(SearchHoldDtlListForWaitFreezeBySkuRequest dto) {
		Page<?> page = PageHelper.offsetPage(dto.getSkipCount(), dto.getMaxResultCount());
		PagerInfo<List<HoldDtlListForWaitFreezeResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlListForWaitFreezeResponse> list = goodsHoldMapper.selectHoldDtlListForWaitFreezeBySku(dto.getItemList());
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	
	/*4*/
	/**
	 * 批次冻结物料选择
	 * 
	 * @param lotno
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<InvHoldByLontnoResponse>> selectInvHoldByLontno(String lotno, Pager<?> pager) {
		Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
		PagerInfo<List<InvHoldByLontnoResponse>> pagerInfo = new PagerInfo<>();
		List<InvHoldByLontnoResponse> list = goodsHoldMapper.selectInvHoldByLontno(lotno);
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	/**
	 * 批次号冻结物料选择=》统计待冻结明细
	 * 
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldDtlListForWaitFreezeResponse>> selectHoldDtlListForWaitFreezeByLontno(SearchHoldDtlListForWaitFreezeByLotnoRequest dto) {
		Page<?> page = PageHelper.offsetPage(dto.getSkipCount(), dto.getMaxResultCount());
		PagerInfo<List<HoldDtlListForWaitFreezeResponse>> pagerInfo = new PagerInfo<>();
		List<HoldDtlListForWaitFreezeResponse> list = goodsHoldMapper.selectHoldDtlListForWaitFreezeByLontno(dto.getItemList());
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
	}
	
	
	
	/**
	 * 根据缓存key查找冻结失败的条码信息
	 * 
	 * @param errorHoldGoodsKey
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<HoldErrorGoodsResponse>> selectErrorHoldGoods(String errorHoldGoodsKey, Pager<?> pager) {
		long start = pager.getSkipCount();
		long end = (pager.getSkipCount() + pager.getMaxResultCount() - 1);
		long totalSize = RedisUtil.lGetListSize(errorHoldGoodsKey);
		
		List<String> snList = (List<String>)(List)RedisUtil.lGet(errorHoldGoodsKey, start, end);
		List<HoldErrorGoodsResponse> list = null;
		if(snList.size() > 0) {
			list = goodsHoldMapper.selectHoldErrorGoodsList(snList);
		} else {
			list = new ArrayList<>(0);
		}
		PagerInfo<List<HoldErrorGoodsResponse>> pagerInfo = new PagerInfo<>();
		pagerInfo.setItems(list);
		pagerInfo.setTotalCount(totalSize);
		return pagerInfo;
	}
	
	/**
	 * 根据缓存key导出冻结失败的条码信息
	 * 
	 * @param errorHoldGoodsKey
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	public void exportErrorHoldGoods(String errorHoldGoodsKey, HttpServletRequest request, HttpServletResponse response) throws Exception {
		long totalSize = RedisUtil.lGetListSize(errorHoldGoodsKey);
		List<String> snList = (List<String>)(List)RedisUtil.lGet(errorHoldGoodsKey, 0, totalSize - 1);
		
		List<HoldErrorGoodsResponse> dataSet = null;
		if(snList.size() > 0) {
			dataSet = goodsHoldMapper.selectHoldErrorGoodsList(snList);
		} else {
			dataSet = new ArrayList<>(0);
		}
		EasyExcelUtil.setResponse(request, response, "冻结异常条码");
		EasyExcelUtil.export(response, HoldErrorGoodsResponse.class, dataSet, "1");
	}
	
	/**
	 * 根据缓存key关闭条码信息
	 * 
	 * @param errorHoldGoodsKey
	 * @return
	 */
	public Result<?> closeErrorHoldGoods(String errorHoldGoodsKey) {
		RedisUtil.delete(errorHoldGoodsKey);
		return new Result<>();
	}
	
	/**
	 * 【库存冻结单-库存冻结】服务
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws Exception 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<String> submitHoldFreeze(SubmitHoldFreezeRequest dto, HttpServletRequest servletRequest) throws Exception {
		HoldHeader holdHeader = holdHeaderMapper.selectById(dto.getHoldHeaderId());
		
		// 检验1【冻结单状态】
		if(Objects.equals(HoldHeaderStatusEnum.ABANDONED.code, holdHeader.getStatus())) {
			Shift.fatal("冻结单状态[已废弃]，不能进行冻结！");
		}
		if(Objects.equals(HoldHeaderStatusEnum.FINISH.code, holdHeader.getStatus())) {
			Shift.fatal("冻结单状态[已完成]，不能进行冻结！");
		}
		
		// 根据查找方式找出条码
		List<SubmitHoldFreezeItemRequest> itemList = dto.getItemList();
		List<HoldDtlGoodsResponse> datas = null;
		switch (dto.getType()) {
		case 1:
			// 按送货单
			for (SubmitHoldFreezeItemRequest item : itemList) {
				item.setAsnNoList(Arrays.asList(item.getAsnNo().split(SeparatorString.COMMA)));
			}
			datas = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeByAsn(itemList, null);
			break;
		case 2:
			// 按检验单
			for (SubmitHoldFreezeItemRequest item : itemList) {
				item.setOqcList(Arrays.asList(item.getOqc().split(SeparatorString.COMMA)));
			}
			datas = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeByOqc(itemList, null);
			break;
		case 3:
			// 按物料/批次号
			datas = goodsHoldMapper.selectHoldDtlGoodsListForWaitFreezeBySkuOrLotno(itemList, null);
			break;
		default:
			Shift.fatal("入参有误，请确认！");
			break;
		}
		
		// 获取goods
		List<String> snList = datas.stream().map(HoldDtlGoodsResponse::getGoodsSn).distinct().collect(Collectors.toList());
		List<GoodsVersion> allGoodsList = goodsVersionService.selectBySnList(snList);
		
		// 不允许冻结【状态(status)等于(0、1、 8、 9、 10、99)的SN或者冻结标识(is_hold)等于1】
		List<GoodsVersion> errorGoodsList = allGoodsList.stream().filter(t -> GoodsStatusEnum.CREATE.code == t.getStatus() || 
				GoodsStatusEnum.WAIT_IN.code == t.getStatus() || GoodsStatusEnum.HAS_CHUKU.code == t.getStatus() || 
				GoodsStatusEnum.HAS_TUIKU.code == t.getStatus() || GoodsStatusEnum.OUT_ONLOAD.code == t.getStatus() || 
				GoodsStatusEnum.SCRAP.code == t.getStatus() || GoodsIsHoldEnum.YES.code == t.getIsHold()).collect(Collectors.toList());
		
		// 允许冻结【状态(status)等于(2、3、 4、 5、6、7)的SN并且冻结标识(is_hold)等于0】
		List<GoodsVersion> okGoodsList = allGoodsList.stream().filter(t -> (GoodsStatusEnum.WAIT_UP.code == t.getStatus() || 
				GoodsStatusEnum.HAS_UP.code == t.getStatus() || GoodsStatusEnum.WAIT_DOWM.code == t.getStatus() || 
				GoodsStatusEnum.HAS_DOWN.code == t.getStatus() || GoodsStatusEnum.HAS_COMFIRM.code == t.getStatus() || 
				GoodsStatusEnum.HAS_ZHUANGGUI.code == t.getStatus()) && GoodsIsHoldEnum.NO.code == t.getIsHold()).collect(Collectors.toList());
		
		// 用户名、当前时间
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		// 当前冻结单最大的行号
		Integer lockMaxHoldLineNo = holdDtlMapper.lockMaxHoldLineNo(holdHeader.getHoldHeaderId());
		if(lockMaxHoldLineNo == null) {
			lockMaxHoldLineNo = 0;
		}
		
		// 根据【仓库、库位、货主、物料、组织、供应商、批次号、库存性质、品质状态】分组统计
		Map<String, List<GoodsVersion>> invGoodsMap = okGoodsList.stream().collect(Collectors.groupingBy(t ->
			(t.getWhsId() + "#" + t.getLocId() + "#" + t.getOwner() + "#" +
		     t.getSkuId() + "#" + t.getFactory() + "#" + t.getVendorId() + "#" +
		     t.getLotno() + "#" + t.getInvAttr() + "#" + t.getQaStatus() + "#"), Collectors.toList()));
		for (String invGoodsKey : invGoodsMap.keySet()) {
			lockMaxHoldLineNo++;
			List<GoodsVersion> goodsList = invGoodsMap.get(invGoodsKey);
			BigDecimal qty = goodsList.stream().map(t -> t.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
			GoodsVersion invGoods = goodsList.get(0);
			
			// 批次号
			Lotno lotno = null;
			if(invGoods.getLotno() != null){
				lotno = lotnoService.selectByLotno(invGoods.getLotno());
			}
			
			// 库区
			Integer zoneId = null;
			if(invGoods.getLocId() != null) {
				Location location = locationMapper.selectById(invGoods.getLocId());
				zoneId = location.getZoneId();
			}
			
			// 【更新库存】
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(invGoods.getWhsId()); 		// 仓库
			input.setOwner(invGoods.getOwner()); 		// 货主
			input.setSkuId(invGoods.getSkuId()); 		// 物料
			input.setFactory(invGoods.getFactory()); 	// 组织
			input.setVendorId(invGoods.getVendorId()); 	// 供应商
			input.setInvAttr(invGoods.getInvAttr()); 	// 库存性质
			input.setQaStatus(invGoods.getQaStatus()); 	// QA状态
			input.setLotNo(invGoods.getLotno());		// 批次号
			input.setLocId(invGoods.getLocId()); 		// 库位ID
			input.setZoneId(zoneId); 					// 库区ID
			input.setUnit(invGoods.getUnit()); 			// 单位
			input.setHoldQty(qty); 						// 【冻结数量+】
			input.setOperator(loginName);
			Integer invLocId = inventoryService.updateLocInventroy(input);
			Integer invZoneId = inventoryService.updateZoneInventory(input);
						
			// 【库存冻结凭证--单头】
			TrsnHeader trsnHeader = new TrsnHeader();
			trsnHeader.setNoteType(TrsnNoteTypeEnum.HOLD_STORAGE.getCode());
			trsnHeader.setStatus(TrsnHeaderStatusEnum.CMP.code);
			trsnHeader.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER));
			trsnHeader.setOwner(invGoods.getOwner());
			trsnHeader.setFactory(invGoods.getFactory());
			trsnHeader.setVendorId(invGoods.getVendorId());
			trsnHeader.setWhsId(invGoods.getWhsId());
			trsnHeader.setFmDoc(holdHeader.getHoldNo());
			trsnHeader.setCreateUser(loginName);
			trsnHeader.setCreateTime(date);
			trsnHeaderMapper.insert(trsnHeader);

			// 【库存冻结凭证--明细】
			TrsnDtl trsnDtl = new TrsnDtl();
			trsnDtl.setNoteLineNo("1");
			trsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.UN_FREEZE.code);
			trsnDtl.setStatus(TrsnDtlStatusEnum.CMP.code);
			trsnDtl.setUnit(invGoods.getUnit());
			trsnDtl.setSkuId(invGoods.getSkuId());
			trsnDtl.setQty(qty);
			trsnDtl.setFmDoc(holdHeader.getHoldNo());
			trsnDtl.setQaStatus(invGoods.getQaStatus());
			trsnDtl.setFmDocLine(String.valueOf(lockMaxHoldLineNo));
			trsnDtl.setNoteNo(trsnHeader.getNoteNo());
			trsnDtl.setTrsnHeaderId(trsnHeader.getTrsnHeaderId());
			trsnDtl.setCreateUser(loginName);
			trsnDtl.setCreateTime(date);
			if(lotno != null) {
				Class<?> lotnoClass = lotno.getClass();
				Class<?> trsnDtlClass = trsnDtl.getClass();
				for (int i = 1; i < 13; i++) {
					Field field = lotnoClass.getDeclaredField("lotAttr" + i);
					Method method = trsnDtlClass.getMethod("setLotAttr" + i, String.class);
					field.setAccessible(true);
					method.setAccessible(true);
					method.invoke(trsnDtl, field.get(lotno));
				}
			}
			trsnDtlMapper.insert(trsnDtl);
			
			// 【写库存冻结单明细(wms_hold_dtl)】
			HoldDtl holdDtl = new HoldDtl();
			holdDtl.setHoldHeaderId(holdHeader.getHoldHeaderId());
			holdDtl.setHoldNo(holdHeader.getHoldNo());
			holdDtl.setHoldLineNo(lockMaxHoldLineNo); // 冻结行号
			holdDtl.setOwner(invGoods.getOwner());
			holdDtl.setFactory(invGoods.getFactory());
			holdDtl.setSkuId(invGoods.getSkuId());
			holdDtl.setVendor(invGoods.getVendorId());
			holdDtl.setInvAttr(invGoods.getInvAttr());
			holdDtl.setQaStatus(invGoods.getQaStatus());
			holdDtl.setLotno(invGoods.getLotno());
			holdDtl.setWhsId(invGoods.getWhsId());
			holdDtl.setZoneId(zoneId);
			holdDtl.setLocId(invGoods.getLocId());
			holdDtl.setQty(qty);
			holdDtl.setUnit(invGoods.getUnit());
			holdDtl.setInvZoneId(invZoneId); // 库区库存ID
			holdDtl.setInvLocId(invLocId); // 库位库存ID
			holdDtl.setHoldBy(loginName);
			holdDtl.setHoldTime(date);
			holdDtl.setStatus(HoldDtlStatusEnum.FREEZE.code);
			holdDtl.setCreateUser(loginName);
			holdDtl.setCreateTime(date);
			holdDtlMapper.insert(holdDtl);
			
			for (GoodsVersion goods : goodsList) {
				// 【库存冻结凭证--明细goods】
				TrsnDtlGoods trsnDtlGoods = new TrsnDtlGoods();
				trsnDtlGoods.setTrsnDtlId(trsnDtl.getTrsnDtlId());
				trsnDtlGoods.setGoodsSn(goods.getGoodsSn());
				trsnDtlGoods.setGoodsId(goods.getGoodsId());
				trsnDtlGoods.setQty(goods.getQty());
				trsnDtlGoods.setQaStatus(goods.getQaStatus());
				trsnDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
				trsnDtlGoods.setCreateTime(date);
				trsnDtlGoods.setCreateUser(loginName);
				trsnDtlGoodsMapper.insert(trsnDtlGoods);
				
				// 【更新goods】
				String oldGoodsJson = JSON.toJSONString(goods); // 原先的json
				goods.setIsHold(1);	// 是否冻结=是
				goods.setModifyUser(loginName);
				goods.setModifyTime(date);
				goodsVersionService.updateById(goods);
				String newGoodsJson = JSON.toJSONString(goods); // 更新后的json
				
				// 【新增goods日志】
				GoodsLog goodsLog = new GoodsLog();
				goodsLog.setInvTransId(trsnDtl.getTrsnDtlId());
				goodsLog.setGoodsSn(goods.getGoodsSn());
				goodsLog.setOpCode(OpCodeEnum.HOLD.getCode());
				goodsLog.setReason(String.format("库存冻结，冻结单[%s]", holdHeader.getHoldNo()));
				goodsLog.setOperator(OpCodeEnum.HOLD.getEnumName());
				goodsLog.setUpdateContent("未更新的:" + oldGoodsJson + ",更新的:" + newGoodsJson);
				goodsLog.setCreateUser(loginName);
				goodsLog.setCreateTime(date);
				goodsLogMapper.insert(goodsLog);
				
				// 【写库存冻结单明细货品清单(wms_hold_dtl_goods)】
				HoldDtlGoods holdDtlGoods = new HoldDtlGoods();
				holdDtlGoods.setHoldDtlId(holdDtl.getHoldDtlId());
				holdDtlGoods.setGoodsSn(goods.getGoodsSn());
				holdDtlGoods.setGoodsId(goods.getGoodsId());
				holdDtlGoods.setQty(goods.getQty());
				holdDtlGoods.setStatus(HoldDtlGoodsStatusEnum.FREEZE.code);
				holdDtlGoods.setCreateTime(date);
				holdDtlGoods.setCreateUser(loginName);
				holdDtlGoodsMapper.insert(holdDtlGoods);
			}
		}
		
		// 返回信息
		String message = null;
		String errorGoodsKey = null;
		if(errorGoodsList.size() > 0) {
			List<String> errorHoldSnList = errorGoodsList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
			message = String.format("以下[%s]个SN由于在冻结期间状态发生变化，无法冻结，请知悉！", errorHoldSnList.size());
			errorGoodsKey = "RAW:HOLD:" + StringUtils.UUID();
			for (String errorHoldSn : errorHoldSnList) {
				RedisUtil.lSet(errorGoodsKey, errorHoldSn);
			}
			// 缓存24小时
			RedisUtil.expire(errorGoodsKey, LockNumber.DAY_SECONDS);
		}
		if(okGoodsList.size() > 0) {
			holdHeader.setStatus(HoldHeaderStatusEnum.FINISH.code);
			holdHeader.setModifyUser(loginName);
			holdHeader.setModifyTime(date);
			holdHeaderMapper.updateById(holdHeader);
			return new Result<>(true, message, errorGoodsKey);
		} else {
			return new Result<>(false, message, errorGoodsKey);
		}
	}
	
	/**
	 * 【库存冻结单-库存解冻】服务
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws Exception 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> submitHoldThaw(SubmitHoldThawRequest dto, HttpServletRequest servletRequest) throws Exception {
		// 解冻单
		HoldHeader holdHeader = holdHeaderMapper.selectById(dto.getHoldHeaderId());
		
		// 检验1【解冻单状态】
		if(Objects.equals(HoldHeaderStatusEnum.ABANDONED.code, holdHeader.getStatus())) {
			Shift.fatal("解冻单状态[已废弃]，不能进行解冻！");
		}
		if(Objects.equals(HoldHeaderStatusEnum.FINISH.code, holdHeader.getStatus())) {
			Shift.fatal("解冻单状态[已完成]，不能进行解冻！");
		}
		
		// 检验2【冻结单明细状态】
		// 【行级锁】控制到每个冻结单明细
		QueryWrapper<HoldDtl> lockWrapper = WrapperUtil.lock(HoldDtl.class);
		lockWrapper.in("HOLD_DTL_ID", dto.getHoldDtlIdList());
		List<HoldDtl> holdDtlList = holdDtlMapper.selectList(lockWrapper);
		HoldDtl errorHoldDtl = holdDtlList.stream().filter(t -> Objects.equals(t.getStatus(), HoldDtlStatusEnum.THAW.code)).findAny().orElse(null);
		if (errorHoldDtl != null) {
			Shift.fatal(String.format("冻结单号/行号[%s/%s]已解冻，不能重复解冻！", errorHoldDtl.getHoldNo(), errorHoldDtl.getHoldLineNo()));
		}
		
		// 用户名、当前时间
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();

		// 当前解冻单最大的行号
		Integer lockMaxHoldLineNo = holdDtlMapper.lockMaxHoldLineNo(holdHeader.getHoldHeaderId());
		if (lockMaxHoldLineNo == null) {
			lockMaxHoldLineNo = 0;
		}
		
		// 遍历处理冻结单
		for (HoldDtl item : holdDtlList) {
			lockMaxHoldLineNo++;
			
			// 批次号
			Lotno lotno = null;
			if(item.getLotno() != null){
				lotno = lotnoService.selectByLotno(item.getLotno());
			}
			
			// 【更新库存】
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(item.getWhsId()); 		// 仓库
			input.setOwner(item.getOwner()); 		// 货主
			input.setSkuId(item.getSkuId()); 		// 物料
			input.setFactory(item.getFactory()); 	// 组织
			input.setVendorId(item.getVendor()); 	// 供应商
			input.setInvAttr(item.getInvAttr()); 	// 库存性质
			input.setQaStatus(item.getQaStatus());	// QA状态
			input.setLotNo(item.getLotno());        // 批次号
			input.setLocId(item.getLocId()); 		// 库位ID
			input.setZoneId(item.getZoneId()); 		// 库区ID
			input.setUnit(item.getUnit()); 			// 单位
			input.setHoldQty(item.getQty().negate()); // 【冻结数量-】
			input.setOperator(loginName);
			Integer invLocId = inventoryService.updateLocInventroy(input);
			Integer invZoneId = inventoryService.updateZoneInventory(input);

			// 【库存解冻凭证--单头】
			TrsnHeader trsnHeader = new TrsnHeader();
			trsnHeader.setNoteType(TrsnNoteTypeEnum.UN_HOLD_STORAGE.getCode());
			trsnHeader.setStatus(TrsnHeaderStatusEnum.CMP.code);
			trsnHeader.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(TRSN_ORDER));
			trsnHeader.setOwner(item.getOwner());
			trsnHeader.setFactory(item.getFactory());
			trsnHeader.setVendorId(item.getVendor());
			trsnHeader.setWhsId(item.getWhsId());
			trsnHeader.setFmDoc(holdHeader.getHoldNo());
			trsnHeader.setCreateUser(loginName);
			trsnHeader.setCreateTime(date);
			trsnHeaderMapper.insert(trsnHeader);

			// 【库存解冻凭证--明细】
			TrsnDtl trsnDtl = new TrsnDtl();
			trsnDtl.setNoteLineNo("1");
			trsnDtl.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.FREEZE.code);
			trsnDtl.setStatus(TrsnDtlStatusEnum.CMP.code);
			trsnDtl.setUnit(item.getUnit());
			trsnDtl.setSkuId(item.getSkuId());
			trsnDtl.setQty(item.getQty());
			trsnDtl.setFmDoc(holdHeader.getHoldNo());
			trsnDtl.setQaStatus(item.getQaStatus());
			trsnDtl.setFmDocLine(String.valueOf(lockMaxHoldLineNo));
			trsnDtl.setNoteNo(trsnHeader.getNoteNo());
			trsnDtl.setTrsnHeaderId(trsnHeader.getTrsnHeaderId());
			trsnDtl.setCreateUser(loginName);
			trsnDtl.setCreateTime(date);
			if (lotno != null) {
				Class<?> lotnoClass = lotno.getClass();
				Class<?> trsnDtlClass = trsnDtl.getClass();
				for (int i = 1; i < 13; i++) {
					Field field = lotnoClass.getDeclaredField("lotAttr" + i);
					Method method = trsnDtlClass.getMethod("setLotAttr" + i, String.class);
					field.setAccessible(true);
					method.setAccessible(true);
					method.invoke(trsnDtl, field.get(lotno));
				}
			}
			trsnDtlMapper.insert(trsnDtl);

			// 【写库存解冻单明细(wms_hold_dtl)】
			HoldDtl holdDtl = new HoldDtl();
			holdDtl.setHoldHeaderId(holdHeader.getHoldHeaderId());
			holdDtl.setHoldNo(holdHeader.getHoldNo());
			holdDtl.setHoldLineNo(lockMaxHoldLineNo); // 解冻行号
			holdDtl.setSourceNo(item.getHoldNo());
			holdDtl.setSourceLineNo(String.valueOf(item.getHoldLineNo()));
			holdDtl.setOwner(item.getOwner());
			holdDtl.setFactory(item.getFactory());
			holdDtl.setSkuId(item.getSkuId());
			holdDtl.setVendor(item.getVendor());
			holdDtl.setInvAttr(item.getInvAttr());
			holdDtl.setQaStatus(item.getQaStatus());
			holdDtl.setLotno(item.getLotno());
			holdDtl.setWhsId(item.getWhsId());
			holdDtl.setZoneId(item.getZoneId());
			holdDtl.setLocId(item.getLocId());
			holdDtl.setQty(item.getQty());
			holdDtl.setUnit(item.getUnit());
			holdDtl.setInvZoneId(invZoneId); 	// 库区库存ID
			holdDtl.setInvLocId(invLocId); 		// 库位库存ID
			holdDtl.setHoldBy(loginName);
			holdDtl.setHoldTime(date);
			holdDtl.setStatus(HoldDtlStatusEnum.THAW.code);
			holdDtl.setCreateUser(loginName);
			holdDtl.setCreateTime(date);
			holdDtlMapper.insert(holdDtl);
			
			// 【写库存解冻单明细货品清单条码(wms_hold_dtl_goods)】
			QueryWrapper<HoldDtlGoods> holdDtlGoodsQueryWrapper = new QueryWrapper<>();
			holdDtlGoodsQueryWrapper.eq("HOLD_DTL_ID", item.getHoldDtlId());
			List<HoldDtlGoods> holdDtlGoodsList = holdDtlGoodsMapper.selectList(holdDtlGoodsQueryWrapper);
			List<String> snList = holdDtlGoodsList.stream().map(HoldDtlGoods::getGoodsSn).distinct().collect(Collectors.toList());
			List<Goods> goodsList = goodsService.selectBySnList(snList);
			for (Goods goods : goodsList) {
				// 【库存解冻凭证--明细goods】
				TrsnDtlGoods trsnDtlGoods = new TrsnDtlGoods();
				trsnDtlGoods.setTrsnDtlId(trsnDtl.getTrsnDtlId());
				trsnDtlGoods.setGoodsSn(goods.getGoodsSn());
				trsnDtlGoods.setGoodsId(goods.getGoodsId());
				trsnDtlGoods.setQty(goods.getQty());
				trsnDtlGoods.setQaStatus(goods.getQaStatus());
				trsnDtlGoods.setStatus(TransferDtlGoodStatusEnum.HAS_RECEIVE.code);
				trsnDtlGoods.setCreateTime(date);
				trsnDtlGoods.setCreateUser(loginName);
				trsnDtlGoodsMapper.insert(trsnDtlGoods);

				// 【更新goods】
				String oldGoodsJson = JSON.toJSONString(goods); // 原先的json
				goods.setIsHold(0);	// 是否冻结=否
				goods.setModifyUser(loginName);
				goods.setModifyTime(date);
				String newGoodsJson = JSON.toJSONString(goods); // 更新后的json
				goodsMapper.updateById(goods);

				// 【新增goods日志】
				GoodsLog goodsLog = new GoodsLog();
				goodsLog.setInvTransId(trsnDtl.getTrsnDtlId());
				goodsLog.setGoodsSn(goods.getGoodsSn());
				goodsLog.setOpCode(OpCodeEnum.RELEASE.getCode());
				goodsLog.setReason(String.format("库存解冻，解冻单[%s]", holdHeader.getHoldNo()));
				goodsLog.setOperator(OpCodeEnum.HOLD.getEnumName());
				goodsLog.setUpdateContent("未更新的:" + oldGoodsJson + ",更新的:" + newGoodsJson);
				goodsLog.setCreateUser(loginName);
				goodsLog.setCreateTime(date);
				goodsLogMapper.insert(goodsLog);

				// 【写库存解冻单明细货品清单(wms_hold_dtl_goods)】
				HoldDtlGoods holdDtlGoods = new HoldDtlGoods();
				holdDtlGoods.setHoldDtlId(holdDtl.getHoldDtlId());
				holdDtlGoods.setGoodsSn(goods.getGoodsSn());
				holdDtlGoods.setGoodsId(goods.getGoodsId());
				holdDtlGoods.setQty(goods.getQty());
				holdDtlGoods.setStatus(HoldDtlGoodsStatusEnum.THAW.code);
				holdDtlGoods.setCreateTime(date);
				holdDtlGoods.setCreateUser(loginName);
				holdDtlGoodsMapper.insert(holdDtlGoods);
			}
			
			// 【更新回写冻结单明细】
			item.setModifyTime(date);
			item.setReleaseTime(date);
			item.setModifyUser(loginName);
			item.setReleaseBy(loginName);
			item.setReleaseComments(String.format("解冻单号/行号[%s/%s]", holdDtl.getHoldNo(), holdDtl.getHoldLineNo()));
			item.setStatus(HoldDtlStatusEnum.THAW.code);
			holdDtlMapper.updateById(item);
		}
		
		// 【处理解冻单表头】
		holdHeader.setStatus(HoldHeaderStatusEnum.FINISH.code);
		holdHeader.setModifyUser(loginName);
		holdHeader.setModifyTime(date);
		holdHeaderMapper.updateById(holdHeader);
		return new Result<>();
	}
}
